/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lolbuilder.mainClasses;

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import lolbuilder.Champions.Impl.GenericChamp;
import lolbuilder.Champions.Interf.DummyChamp;
import lolbuilder.Items.Impl.*;
import lolbuilder.Items.Interf.ItemsSuper;
import lolbuilder.build.Build;
import lolbuilder.calculation.CalculateValueOfAdItems;
import lolbuilder.calculation.FightThread;
import lolbuilder.fights.FightResult;
import lolbuilder.fights.Versus;
import lolbuilder.masteries.BestDpsMasteriesChoose;
import lolbuilder.params.Duo;
import lolbuilder.params.Parameters;
import lolbuilder.runes.RBS;
import lolbuilder.runes.RunesCompoCalculator;

/**
 *
 * @author chocoboSan
 */
public class BestBuildFromFights {
    //public static HashMap<Versus,FightResult> whoWon=new HashMap<Versus,FightResult>();
    public static Stack<Duo<Build,Integer>> buildsWithNotes=new Stack<Duo<Build,Integer>>();
    public static ArrayList<Build> builds=new ArrayList<Build>();
    public static int bestNote;
    public static Integer finished=0;
    public static int nb_thread=Runtime.getRuntime().availableProcessors();
    
    public static void main(String[] args) {
        AllItems.populate();
        BestDpsMasteriesChoose.main(args);
        RunesCompoCalculator.main(args);
        float noteMoyenne=0;
        
        float maxDPS=0;
        ItemsSuper bestDPS=null;
        for (ItemsSuper i : AllItems.items) {
            if (i.isAdItem) {
                Build b=new Build();
                b.items.add(i);
                DummyChamp c =null;
                try {
                    c=Parameters.champUsedForAd.getClass().newInstance();
                } catch (InstantiationException ex) {
                    Logger.getLogger(CalculateValueOfAdItems.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IllegalAccessException ex) {
                    Logger.getLogger(CalculateValueOfAdItems.class.getName()).log(Level.SEVERE, null, ex);
                }
                b.applyThisBuild(c);
                c.calculateDpsOver5sec();
                if (c.dpsOver5sec>maxDPS) {
                    bestDPS=b.items.get(0);
                }
            }
        }
        Build BestDpsBuild=new Build();
        
        for (int foi=0;foi<6;foi++) {
            BestDpsBuild.items.add(bestDPS);
        }
        
        
        try {
                    System.out.println("reading file, plz wait this might take a while...");
                    for (int j=0;j<=100;j++) {
                        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("toto"+j+".bin"));
                        builds.addAll((ArrayList<Build>) inputStream.readObject());
                        inputStream.close();
                        System.out.println(j+ "% chargé");
                    }
                    Collections.shuffle(builds);
                } catch (Exception ex) {
                    Logger.getLogger(ItemBuildGeneratorFromFile.class.getName()).log(Level.SEVERE, null, ex);
                }
        System.out.println("Chargé");
        
        
        System.out.println("calcul de la première meilleur note");
        DummyChamp g1=null;
         try {
            g1 = Parameters.champUsedForAd.getClass().newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(ItemBuildGenerator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ItemBuildGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
        DummyChamp g2=null;
         try {
            g2 = Parameters.champUsedForAd.getClass().newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(ItemBuildGenerator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ItemBuildGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
        Parameters.r.addAllBonus(g1);
        Parameters.mbc.applyMasteries(g1);
        BestDpsBuild.applyThisBuild(g1);
        RBS ennemyRunes=new RBS();
        ennemyRunes.ad+=15;
        ennemyRunes.armr+=13;
        ennemyRunes.rm+=12;
        float step=(float) 0.1;
        int toTestNote=(int) (BestBuildFromFights.builds.size());
        for (Build b2 : BestBuildFromFights.builds) {
            g2.resetStats();
            /*Versus v=new Versus(new Duo<Build,Build>(toTest,b2));
            FightResult whoWon=BestBuildFromFights.whoWon.get(v);
            if (whoWon!=null) {
                if (whoWon.whowon==0) {
                    if (whoWon.fight.matchup.a.equals(toTest)) {
                        continue;
                    } else {
                        toTestNote--;
                    }
                } else if (whoWon.whowon==1) {
                    if (whoWon.fight.matchup.b.equals(toTest)) {
                        continue;
                    } else {
                        toTestNote--;
                    }
                }
            }*/

            ennemyRunes.addAllBonus(g2);
            Parameters.mbc.applyMasteries(g2);
            b2.applyThisBuild(g2);
            int curH1=g1.hp;
            int curH2=g2.hp;
            float i=0;
            while (curH1>0 && curH2>0 && i<5) {
                    float MgcDamage1=g1.calculateMyMagicDmgForThisNumberOfSecOnThisTarget(g2, step);
                    float MgcDamage2=g2.calculateMyMagicDmgForThisNumberOfSecOnThisTarget(g1, step);
                
                    float damage1=(g1).calculateMyDmgsForThisNumberOfSecOnThisTarget(g2,step);
                
                    float damage2=(g2).calculateMyDmgsForThisNumberOfSecOnThisTarget(g1,step);
                    float regenHp1PerStep=(((float)g1.regenhp)/5)*step;
                    float regenHp2PerStep=(((float)g2.regenhp)/5)*step;
                
                
                curH1=(int) (((float)curH1)-damage2-MgcDamage2);
                curH1+=regenHp1PerStep;
                if (g1.ls>0) curH1+=((damage1*g1.ls)/100);
                if (g1.sv>0) curH1+=((MgcDamage1*g1.sv)/100);
                g1.curHp=curH1;

                curH2=(int) (((float)curH2)-damage1-MgcDamage1);
                curH2+=regenHp2PerStep;
                if (g2.ls>0) curH2+=(damage2*g2.ls/100);
                if (g2.sv>0) curH1+=((MgcDamage1*g2.sv)/100);
                g2.curHp=curH2;
                
                g1.updateTick(step);
                g2.updateTick(step);
                i+=step;
            }
            /*if (curH1<curH2) {
                BestBuildFromFights.whoWon.put(v, new FightResult(v, 0));
            } else {
                BestBuildFromFights.whoWon.put(v, new FightResult(v, 1));
            }*/
            if (curH1<curH2) {
                toTestNote--;
            }
        }
        bestNote=toTestNote;System.out.println("first best note : "+bestNote);
        
        int jj=0;
        int size=builds.size();
        Build bestBuild=null;
        int curNote;
        //GenericChamp g1=new GenericChamp();
        //GenericChamp g2=new GenericChamp();
        bestNote=0;
        ArrayList<FightThread> thr=new ArrayList<FightThread>();
        int cpt_t;
        for (cpt_t=0;cpt_t<nb_thread;cpt_t++) {
            thr.add(new FightThread());
        }
        //int whichT=0;
        int deb=0;
        int segment=builds.size()/nb_thread;
        for (cpt_t=0;cpt_t<nb_thread;cpt_t++) {
            if (cpt_t==nb_thread-1) {
                thr.get(cpt_t).pool.addAll(builds.subList(deb, builds.size()));
                thr.get(cpt_t).start();
                deb+=segment;
            } else {
                thr.get(cpt_t).pool.addAll(builds.subList(deb, deb+segment));
                thr.get(cpt_t).start();
                deb+=segment;
            }
        }
        /*for (Build b1 : builds) {
            curNote=size;
            
            boolean good=true;
            /*g1.resetStats();
            b1.applyThisBuild(g1);
            for (Build b2 : builds) {
                g2.resetStats();
                b2.applyThisBuild(g2);
                int curH1=g1.hp;
                int curH2=g2.hp;
                float step=(float) 0.1;
                float i=0;
                float critLuck1=g1.critP/100;
                float critLuck2=g2.critP/100;
                float nbAttacks1ForOneSec=1/g1.as;
                float Dmg1=nbAttacks1ForOneSec*g1.ad+(g1.critD-199)*nbAttacks1ForOneSec*critLuck1;
                float damage1=Dmg1-Dmg1*g1.getPercentReducForArmorPen(g2.arm);
                float nbAttacks2ForOneSec=1/g2.as;
                float Dmg2=nbAttacks2ForOneSec*g2.ad+(g2.critD-199)*nbAttacks2ForOneSec*critLuck2;
                float damage2=Dmg2-Dmg2*g2.getPercentReducForArmorPen(g1.arm);

                float regenHp1PerStep=(((float)g1.regenhp)/5)*step;
                float regenHp2PerStep=(((float)g2.regenhp)/5)*step;
                while (curH1>0 && curH2>0 && i<5) {
                    curH1=(int) (((float)curH1)-damage2/(1/step));
                    curH1+=regenHp1PerStep;
                    if (g1.ls>0) curH1+=(damage1/(1/step)*g1.ls/100);
                    curH2=(int) (((float)curH2)-damage1/(1/step));
                    curH2+=regenHp2PerStep;
                    if (g2.ls>0) curH2+=(damage2/(1/step)*g2.ls/100);
                    i+=step;
                }
                if (curH1<=0 || curH1<curH2) {
                    curNote--;
                    good=false;
                    break;
                }
            }
            /*if (curNote>bestNote) {
                bestNote=curNote;
                bestBuild=b1;
            }*/
            /*if (good==true) {
                System.out.println("one horrible build beats all : "+b1.items);
                return;
            }
            if (jj%5000==0) System.out.println("searched in "+jj+" builds out of "+size);*/
            
          
        //}*/
        for (cpt_t=0;cpt_t<nb_thread;cpt_t++) thr.get(cpt_t).stop=true;
        
        while (!BestBuildFromFights.buildsWithNotes.isEmpty() || finished!=nb_thread) {
            if (!BestBuildFromFights.buildsWithNotes.isEmpty()) {
                Duo<Build,Integer> b=BestBuildFromFights.buildsWithNotes.pop();
                noteMoyenne=(noteMoyenne+b.b);
                if (b.b>BestBuildFromFights.bestNote) {
                    BestBuildFromFights.bestNote=b.b;
                    bestBuild=b.a;
                }
                jj++;
                if (jj%100==0) System.out.println(""+jj+" builds tested over "+BestBuildFromFights.builds.size());
                //System.gc();
            }
            try {
                Thread.sleep(5);
            } catch (InterruptedException ex) {
                Logger.getLogger(BestBuildFromFights.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        System.out.println("NoteMoyenne : "+ (((float)noteMoyenne)/builds.size()));
        System.out.println("best build : " + bestBuild.items);
        System.out.println("best note : "+bestNote);
    }
}
